use crate::model::satori::SatoriUser;
use crate::model::sys_user::SysUser;
use crate::security::LoginPath;
use crate::util::Config;
use crate::ws::AppState;
use axum::extract::{ConnectInfo, Path, State, WebSocketUpgrade};
use axum::http::HeaderMap;
use axum::response::IntoResponse;
use axum::routing::{get, post};
use axum::{Json, Router};
use std::net::SocketAddr;
use tokio::net::TcpListener;
use uuid::Uuid;
use void_log::log_info;

pub mod message;
pub mod guild;
pub mod guild_member;

pub fn get_user_token(headers: HeaderMap) -> Option<String> {
    if let Some(authorization) = headers.get("authorization") {
        Option::from(authorization.to_str().unwrap().trim_start_matches("Bearer ").to_string())
    } else { None }
}

async fn handler(ws: WebSocketUpgrade,
                 State(app_state): State<AppState>,
                 headers: HeaderMap, ConnectInfo(addr): ConnectInfo<SocketAddr>) -> impl IntoResponse {
    log_info!("Connection address {}", &addr.to_string());
    log_info!("WebSocket connection headers {:?}", &headers);
    ws.on_upgrade(move |socket| app_state.handle_socket(socket, headers))
}

async fn get_users(State(app_state): State<AppState>) -> impl IntoResponse {
    let res = SysUser::select_all(&app_state.pool).await.unwrap();
    Json(res)
}

async fn get_user(State(app_state): State<AppState>, Path(id): Path<Uuid>) -> impl IntoResponse {
    let res = SatoriUser::select(&app_state.pool, &id).await.unwrap();
    Json(res)
}

async fn passwd(Path(passwd): Path<String>) -> impl IntoResponse {
    bcrypt::hash(passwd, bcrypt::DEFAULT_COST).unwrap()
}

async fn login_check(State(app_state): State<AppState>, Json(login_path): Json<LoginPath>) -> impl IntoResponse {
    let res = login_path.clone().login(&app_state.pool).await.new();
    if let Some(token) = &res.token {
        log_info!("Token: {}", token);
        app_state.user_token.insert(token.to_string(), res.userid.unwrap());
    }
    Json(res)
}

impl AppState {
    pub async fn server(self) -> std::io::Result<()> {
        let server = Config::get().await.server.unwrap_or_default();
        let host = server.host.unwrap_or_default();
        let port = server.port.unwrap_or_default();

        let mut app = Router::new()
            .route("/", get(|| async { "This is an Chat Server!" }))
            .route("/events", get(handler))
            .route("/login_check", post(login_check))

            // test
            .route("/users", get(get_users))
            .route("/user/{name}", get(get_user))
            .route("/passwd/{passwd}", get(passwd));
        app = message::router(app).await;
        app = guild::router(app).await;
        app = guild_member::router(app).await;
        let app = app.with_state(self.clone());
        let app = Router::new().nest("/v1", app);

        let mut port_add = 0;
        loop {
            if let Ok(listener) = TcpListener::bind(format!("{}:{}", host, port + port_add)).await {
                log_info!("启动端口: {}", port + port_add);
                axum::serve(listener, app.clone().into_make_service_with_connect_info::<SocketAddr>()).await?;
            } else {
                log_info!("端口占用: {port}");
                port_add += 1;
            };
        }
    }
}